/*
 * Copyright (c) 1989 - 1999 Microsoft Corporation
 */

#include "precomp.h"
#pragma hdrstop

#include "mrxglobs.h"
#include "host_access.h"

NTSTATUS
ExecuteCreateSrvCall(
    PMRX_SRVCALL_CALLBACK_CONTEXT  pCallbackContext)
{
    // Fill the RDBSS created SrvCall instance
    // with the information required by the mini redirector.

    NTSTATUS  Status;
    BOOLEAN   Verifyer;
    PHWFS_DEVICE_EXTENSION pDevExt;

    PMRX_SRVCALLDOWN_STRUCTURE SrvCalldownStructure =
        pCallbackContext->SrvCalldownStructure;

    PMRX_SRV_CALL pSrvCall = SrvCalldownStructure->SrvCall;

    ASSERT(pSrvCall);
    ASSERT(NodeType(pSrvCall) == RDBSS_NTC_SRVCALL);

    pDevExt = ((PHWFS_DEVICE_EXTENSION)((PUCHAR)(pSrvCall->RxDeviceObject) + sizeof(RDBSS_DEVICE_OBJECT)));

    // validate the server name with the name of 'HwSf' or 'hwsf'
    HWFS_DBG_PRINT(DBG_INFO, DBG_SESSION,
        ("HwFs - SrvCall: Connection Name Length: %d; %wZ\n",
            pSrvCall->pSrvCallName->Length, pSrvCall->pSrvCallName));

    Verifyer = FALSE;

    Status = HostAccessInit(pDevExt);
    if (!NT_SUCCESS(Status)) {
        HWFS_DBG_PRINT(DBG_INFO, DBG_SESSION, ("Virtio is not initialized yet\n"));
    } else if (pSrvCall->pSrvCallName->Length > sizeof(WCHAR)) {
        // Check srvname is "hwfs"
        PWCHAR pSrvName = pSrvCall->pSrvCallName->Buffer;
        Verifyer = CheckRootName(
            pSrvName, pSrvCall->pSrvCallName->Length,
            HWFS_SRV_NAME, HWFS_SRV_NAME_SIZE);
    } else {
        Verifyer = FALSE;
    }

    if (Verifyer) {
        HWFS_DBG_PRINT(DBG_INFO, DBG_SESSION, ("SrvName matched\n"));
        Status = STATUS_SUCCESS;
    } else {
        HWFS_DBG_PRINT(DBG_INFO, DBG_SESSION, ("skipped SrvName\n"));
        Status = STATUS_BAD_NETWORK_PATH;
    }

    pCallbackContext->Status = Status;
    SrvCalldownStructure->CallBack(pCallbackContext);

    return Status;
}


NTSTATUS
HwFsCreateSrvCall(
    PMRX_SRV_CALL                  pSrvCall,
    PMRX_SRVCALL_CALLBACK_CONTEXT  pCallbackContext)
{
    // Fill the RDBSS created SrvCall instance
    // with the information required by the mini redirector.
    NTSTATUS Status;

    PMRX_SRVCALLDOWN_STRUCTURE SrvCalldownStructure =
        (PMRX_SRVCALLDOWN_STRUCTURE)(pCallbackContext->SrvCalldownStructure);

    ASSERT(pSrvCall);
    ASSERT(NodeType(pSrvCall) == RDBSS_NTC_SRVCALL);

    // If we are in the RDBSS context, ExecuteCreatSrvCall immediately.
    // Otherwise, queue it to worker thread.
    if (IoGetCurrentProcess() == RxGetRDBSSProcess()) {
        HWFS_DBG_PRINT(DBG_TRACE, DBG_SESSION,
            ("CreateSrvCall in context of RDBSS process\n"));

        Status = ExecuteCreateSrvCall(pCallbackContext);
    } else {
        HWFS_DBG_PRINT(DBG_TRACE, DBG_SESSION,
            ("CreateSrvCall Dispatching to worker thread\n"));

        Status = RxDispatchToWorkerThread(
                   g_hwFsDeviceObject,
                   DelayedWorkQueue,
                   ExecuteCreateSrvCall,
                   pCallbackContext);
        if (Status == STATUS_SUCCESS) {
            // Call was pended in worker thread
            Status = STATUS_PENDING;
        }
    }

    return Status;
}


NTSTATUS
HwFsFinalizeSrvCall(
    PMRX_SRV_CALL pSrvCall,
    BOOLEAN       Force)
{
    // Destroy SrvCall instance
    HWFS_DBG_PRINT(DBG_TRACE, DBG_SESSION, ("HwFsFinalizeSrvCall\n"));
    pSrvCall->Context = NULL;

    return STATUS_SUCCESS;
}

NTSTATUS
HwFsSrvCallWinnerNotify(
    IN PMRX_SRV_CALL  pSrvCall,
    IN BOOLEAN        ThisMinirdrIsTheWinner,
    IN OUT PVOID      pSrvCallContext
    )
{
    // Finalize the mini rdr context associated with an RDBSS Server call instance
    // The two phase construction protocol for Server calls is required
    // because of parallel initiation of a number of mini redirectors.
    // The RDBSS finalizes the particular mini redirector to be used in communicating
    // with a given server based on quality of service criterion.
    NTSTATUS Status = STATUS_SUCCESS;

    HWFS_DBG_PRINT(DBG_TRACE, DBG_SESSION, ("HwFsSrvCallWinnerNotify\n"));
    if (ThisMinirdrIsTheWinner) {
        HWFS_DBG_PRINT(DBG_TRACE, DBG_SESSION, ("This minirdr is the winner\n"));
    }

    pSrvCall->Context = (PVOID)0xDEADBEEFDEADBEEF;

    return(Status);
}
